package com.rent.appointment.service.serviceImpl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.rent.appointment.dao.ApplyViewDao;
import com.rent.appointment.dto.ApplyViewDto;
import com.rent.appointment.entity.ApplyView;
import com.rent.appointment.service.AppointmentService;
import com.rent.common.constant.CommonConstant;
import com.rent.common.entity.ApplyMessageDto;
import com.rent.common.exception.BusinessException;
import com.rent.common.interceptor.UserContext;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Service
public class AppointmentServiceImpl extends ServiceImpl<ApplyViewDao,ApplyView> implements AppointmentService {
    @Autowired
    private RedissonClient redissonClient;
    @Autowired
    private ApplyViewDao applyViewDao;
    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Override
    public void createAppointment(ApplyViewDto applyViewDto) {
        //创建实体类，把dto转成entity
        ApplyView applyView = new ApplyView();
        BeanUtils.copyProperties(applyViewDto,applyView);

        Long userId = UserContext.getUserId();
        Long houseId = applyView.getHouseId();

        String lockKey = CommonConstant.LOCK_APPOINTMENT_PREFIX + userId + ":" + houseId;

        RLock lock = redissonClient.getLock(lockKey);
        try {
            if (lock.tryLock(10, 30, TimeUnit.SECONDS)) {
                // 检查是否已预约
                ApplyView existApply = getBaseMapper().selectByUserIdAndHouseId(userId, houseId);
                if (existApply != null) {
                    throw new BusinessException("您已经预约过该房源");
                }

                // 创建预约
                applyView.setUserId(userId);
                applyViewDao.insert(applyView);

                //发送消息通知房东
                ApplyMessageDto amDto = ApplyMessageDto.builder()
                        .id(applyView.getId())
                        .userId(applyView.getUserId())
                        .houseId(applyView.getHouseId())
                        .landlordId(applyView.getLandlordId())
                        .appointmentTime(applyView.getAppointmentTime())
                        .status(applyView.getStatus())
                        .createTime(applyView.getCreateTime())
                        .updateTime(applyView.getUpdateTime())
                        .contactPhone(applyView.getContactPhone())
                        .handleTime(applyView.getHandleTime())
                        .build();

                rabbitTemplate.convertAndSend(
                        CommonConstant.EXCHANGE_NAME,
                        CommonConstant.ROUTING_KEY_APPOINTMENT,
                        amDto
                );

            } else {
                throw new BusinessException("请勿重复提交");
            }
        } catch (InterruptedException e) {
            throw new BusinessException("预约失败");
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    @Override
    public void deleteView(Long id) {
        //根据id获得实体类
        ApplyView applyView = getById(id);
        Long userId = UserContext.getUserId();
        Long houseId = applyView.getHouseId();
        String lockKey = CommonConstant.LOCK_APPOINTMENT_PREFIX + userId + ":" + houseId;

        RLock lock = redissonClient.getLock(lockKey);
        try {
            if (lock.tryLock(10, 30, TimeUnit.SECONDS)) {
                // 检查是否已预约

                //如果房东未处理不通知房东，如果房东处理了 通知房东
                // 检查是否已预约
                ApplyView existApply = getBaseMapper().selectByUserIdAndHouseId(userId, houseId);
                if (null == existApply) {
                    throw new BusinessException("该预约不存在！");
                }
                // 检查是否已经处理预约
                if (3 == existApply.getStatus()){
                    throw  new BusinessException("预约已取消！");
                }else if(1 == existApply.getStatus() || 2 == existApply.getStatus()){
                    // 更新预约信息（其实应该是把status更新为3）
                    applyView.setStatus(3);
                    applyViewDao.updateById(applyView);

                    //发送消息通知房东，房东处理过预约请求，取消预约理应通知房东
                    ApplyMessageDto amDto = ApplyMessageDto.builder()
                            .id(applyView.getId())
                            .userId(applyView.getUserId())
                            .houseId(applyView.getHouseId())
                            .landlordId(applyView.getLandlordId())
                            .appointmentTime(applyView.getAppointmentTime())
                            .status(applyView.getStatus())
                            .createTime(applyView.getCreateTime())
                            .updateTime(applyView.getUpdateTime())
                            .contactPhone(applyView.getContactPhone())
                            .handleTime(applyView.getHandleTime())
                            .build();

                    rabbitTemplate.convertAndSend(
                            CommonConstant.EXCHANGE_NAME,
                            CommonConstant.ROUTING_KEY_APPOINTMENT,
                            amDto
                    );
                    //消息通知完再删除
                    // 取消预约信息(在表里面删除)
                    applyViewDao.deleteById(applyView);

                }else if (0 == existApply.getStatus()){
                    //房东尚未处理消息，租客取消预约不用通知房东
                    // 更新预约信息（其实应该是把status更新为3）
                    applyView.setStatus(3);
                    applyViewDao.updateById(applyView);

                    // 取消预约信息(在表里面删除)
                    applyViewDao.deleteById(applyView);
                }
            } else {
                throw new BusinessException("请先创建预约");
            }
        } catch (InterruptedException e) {
            throw new BusinessException("取消预约失败");
        } finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }


    //使用消息队列处理预约消息（先用分布式锁改状态，再用消息队列发通知）
    public void handleView(Long Id, Integer status) {
        //直接从这里把错误传参处理 如果传的status值为0 返回
        //判断是否处理成功（有可能传的status值是0）
        if ( status.equals(0)){
            throw  new BusinessException("预约处理失败，请选择同意或是拒绝！");
        }else {
            //分布式锁更新状态方法
            //先通过id获取applyView对象
            ApplyView applyView = applyViewDao.selectById(Id);
            //userContext获取的是当前登陆用户，也就是说正在处理预约的房东id
            Long landlordId = UserContext.getUserId();

            String lockKey = CommonConstant.LOCK_PREFIX + landlordId + ":" + Id;

            RLock lock = redissonClient.getLock(lockKey);
            try {
                if (lock.tryLock(10, 30, TimeUnit.SECONDS)) {
                    // 检查是否已预约 （这里是通过id拿到的对象，理论上应该存在，不然走不到这里）
                    ApplyView existApply = getBaseMapper().selectById(Id);
                    /*
                    if (null == existApply) {
                        throw new BusinessException("该预约不存在！");
                    }*/
                    // 检查是否已经处理预约
                    if (3 == existApply.getStatus()){
                        throw  new BusinessException("预约已取消！");
                    }else if(1 == existApply.getStatus() || 2 == existApply.getStatus()){
                        throw  new BusinessException("预约已处理，请勿重复处理！");
                    }

                    // 更新预约信息
                    applyView.setStatus(status);
                    applyViewDao.updateById(applyView);

                } else {
                    throw new BusinessException("请先创建预约！");
                }
            } catch (InterruptedException e) {
                throw new BusinessException("修改预约失败！");
            } finally {
                if (lock.isHeldByCurrentThread()) {
                    lock.unlock();
                }
            }

            //发送消息通知租客已经处理了预约
            ApplyMessageDto amDto = ApplyMessageDto.builder()
                    .id(applyView.getId())
                    .userId(applyView.getUserId())
                    .houseId(applyView.getHouseId())
                    .landlordId(applyView.getLandlordId())
                    .appointmentTime(applyView.getAppointmentTime())
                    .status(applyView.getStatus())
                    .createTime(applyView.getCreateTime())
                    .updateTime(applyView.getUpdateTime())
                    .contactPhone(applyView.getContactPhone())
                    .handleTime(applyView.getHandleTime())
                    .build();

            rabbitTemplate.convertAndSend(
                    CommonConstant.EXCHANGE_NAME,
                    CommonConstant.ROUTING_KEY_APPOINTMENT,
                    amDto
            );
        }

    }
}
